package ch.uzh.ifi.seal.ssqa.importer.code;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;

import ch.uzh.ifi.seal.ssqa.model.CClass;
import ch.uzh.ifi.seal.ssqa.model.ModelFactory;

public class SourceCodeVisitor extends ASTVisitor {

	private List<CClass> classes;

	private List<String> functions;

	private int count = 0;

	private int complexity = 0;

	public SourceCodeVisitor() {
		super();
		this.classes = new ArrayList<CClass>();
		this.functions = new ArrayList<String>();
		this.shouldVisitDeclarations = true;
		this.shouldVisitStatements = true;
	}

	public int visit(IASTDeclaration decl) {
		try {
			if ((decl instanceof IASTSimpleDeclaration)
					&& decl.isPartOfTranslationUnitFile()) {
				IASTSimpleDeclaration simpDecl = (IASTSimpleDeclaration) decl;
				IASTDeclSpecifier declSpecifier = simpDecl.getDeclSpecifier();
				if (declSpecifier instanceof IASTCompositeTypeSpecifier) {
					IASTCompositeTypeSpecifier compTypeSpecifier = (IASTCompositeTypeSpecifier) declSpecifier;
					int key = compTypeSpecifier.getKey();
					if (key == ICPPASTCompositeTypeSpecifier.k_class) {
						IASTName astName = compTypeSpecifier.getName();
						IBinding binding = astName.resolveBinding();
						if (binding instanceof ICPPClassType) {
							ICPPClassType cppClass = (ICPPClassType) binding;
							CClass clazz = ModelFactory.eINSTANCE
									.createCClass();
							clazz.setName(cppClass.getName());
							for (ICPPMethod method : cppClass.getDeclaredMethods()) {
								clazz.getMethodNames().add(method.getName());
							}
							this.classes.add(clazz);
						}
					}
				}
			}
			return PROCESS_CONTINUE;
		} catch (Exception e) {
			System.out.println("Error: " + e.getMessage());
			return PROCESS_SKIP;
		}
	}

	public int visit(IASTStatement statement) {
		try {
			if (!statement.isPartOfTranslationUnitFile()) {
				return PROCESS_SKIP;
			}
			if (statement instanceof IASTIfStatement
					|| statement instanceof IASTDoStatement
					|| statement instanceof IASTForStatement
					|| statement instanceof IASTWhileStatement
					|| statement instanceof IASTCaseStatement) {
				this.complexity++;
			} else {
			}
		} catch (Exception e) {
			return PROCESS_SKIP;
		}
		return PROCESS_CONTINUE;
	}

	public List<CClass> getClasses() {
		return this.classes;
	}

	public int getComplexity() {
		return this.complexity;
	}
}
